#include "swagme.h"
#include "Character.h"
#include "Sprite.h"
#include <algorithm>

const int Character::FrameCount = 3;

Character::Character(Sprite* _ps, int _x, int _y, double _unitsPerMs)
  : TouchableObject(_x, _y, 12, 12),
  Facing(sm_dir_right), prevFacing(sm_dir_right), FrameCounter(0) {
  Init(_ps,_x,_y,_unitsPerMs);
}

Character::Character(Sprite* ps)
  : TouchableObject(0, 0, 12, 12), Facing(sm_dir_right), prevFacing(sm_dir_right), FrameCounter(0) {
  Init(ps,0,0,0.0);
}

Character::Character()
  : TouchableObject(0, 0, 12, 12), Facing(sm_dir_right), prevFacing(sm_dir_right), FrameCounter(0) {
  Init(NULL,0,0,0.0);
}

void Character::Init(Sprite* ps, int _x, int _y, double _unitsPerMs)  {
  mpSprite = ps;
  box.x = _x;
  box.y = _y;
  prevX = _x;
  prevY = _y;
  mUnitsPerMs = _unitsPerMs;
}

void Character::updatePrevPos() {
  prevX = getLeft();
  prevY = getTop();
}

int Character::AddEffect(const string &name) {
  Effect *effect = mpSprite->getEffect(name);
  if (effect) {
    mActiveEffects.push_back(name);
    effect->setFrameCounter(0);
  } else {
    cout << "Error: Attempt to add an effect " << name << " which has not been loaded." << endl;
  }
  return 0;
}

int Character::RemoveEffect(const string &name) {
  ActiveEffectIter aeIt;
  while( (aeIt = find(mActiveEffects.begin(), mActiveEffects.end(), name)) != mActiveEffects.end() ) {
    mActiveEffects.erase(aeIt);
  }
  return 0;
}

int Character::Draw(SDL_Surface *dst, bool bShadow) {
  int frameNum ;
  int nResult;

  if ( (getLeft() != prevX) || (getTop() != prevY)) {
    if (++FrameCounter > FrameCount * 4) FrameCounter = 0;
    frameNum = (FrameCounter /4) % FRAMES_PER_ANIM;
  } else {
    FrameCounter = 1;
    frameNum = 1;
  }
  nResult = mpSprite->Draw(Facing -1, frameNum,dst, (int)(getLeft()+MAP_POS_X), (int)(getTop()+MAP_POS_Y), bShadow);

  // draw effects
  ActiveEffectIter aeIt = mActiveEffects.begin(); 
  while(aeIt != mActiveEffects.end()) {
    Effect* theEffect = mpSprite->getEffect(*aeIt); // pmEffects is a pointer to a collection of pointers
    if (theEffect) {
      theEffect->animNextFrame();
      // hard-coded to loop animation only once for now 
      if (theEffect->getPlayCounter() >= 1) { 
        // NOTE: we don't call RemoveEffect() here for efficiency reasons
        aeIt = mActiveEffects.erase(aeIt);
      } else {
        nResult += mpSprite->DrawEffect(Facing -1, theEffect->getFrameCounter(), dst, (int)(getLeft()+MAP_POS_X), (int)(getTop()+MAP_POS_Y), *aeIt);
        ++aeIt;
      }
    } else {
      aeIt = mActiveEffects.erase(aeIt);
      cerr << "Sprite has no effect for " << *aeIt << endl;
    }
  } // loop for each effect
  return nResult; // TODO: nResult is only valid for a check of 0 or non-zero, the SDL error codes may be invalid
}

// Facing has a setter and getter method so facing changes can be animated if need be
void Character::SetFacing(sm_direction f) {
  prevFacing = Facing;
  Facing = f;
}
sm_direction Character::GetFacing() const {
  return Facing;
}

void Character::SetSpeed(double newSpeed) {
  this->mUnitsPerMs = newSpeed;
}
double Character::GetSpeed() const {
  return this->mUnitsPerMs;
}

Character::~Character() {
}

void Character::move(double newLeft, double newTop) {
  box.x = newLeft;
  box.y = newTop;
}
